package com.tau.egonetwork.gui; 
   
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Future;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import com.tau.egonetwork.common.Configurations;
import com.tau.egonetwork.common.Log;
import com.tau.egonetwork.excel.ExcelReadUtils;
import com.tau.egonetwork.excel.IExcelRead;
import com.tau.egonetwork.exceptions.ExcelCastException;
import com.tau.egonetwork.gui.core.BasicTab;
import com.tau.egonetwork.gui.core.EgoNetworkMessageBox;
import com.tau.egonetwork.gui.core.FileOpenDialog;
import com.tau.egonetwork.gui.core.ProfileTab;
import com.tau.egonetwork.gui.facebook.FacebookProfileTab;
import com.tau.egonetwork.gui.facebook.FacebookTab;
import com.tau.egonetwork.gui.interfaces.IRequestGUI;
import com.tau.egonetwork.gui.linkedin.LinkedinProfileTab;
import com.tau.egonetwork.gui.linkedin.LinkedinTab;
import com.tau.egonetwork.profiles.MainProfile;
import com.tau.egonetwork.profiles.Profile;
import com.tau.egonetwork.profiles.ProfileFile;
import com.tau.egonetwork.profiles.ProfileFile.SocialNetworks;
import com.tau.egonetwork.threads.core.EgoNetworkCallable;
import com.tau.egonetwork.threads.core.ThreadPool;
   
public class MainWindow { 
   
	private static final String KEY_FACEBOOK = "Facebook";
	private static final String KEY_LINKEDIN = "Linkedin";
	private static final String KEY_PROFILE = "Profile";
	private static final String KEY_PROFILE_TYPE = "ProfileType";
	private static final String KEY_ERROR = "Error";
	
	private static Display display;
	private static TabFolder tabs;
	
	private static MenuItem saveMenuItem;
	
	private static Table requestsTable;
	private static final String[] columns = { "", "", "Profile", "Time" };
    private static final int[] alignments = { SWT.CENTER, SWT.CENTER, SWT.LEFT, SWT.CENTER };
    private static final int[] width = { 22, 22, 0, 70 };

    public static void open() {
    	
    	Log.writeLineToLog("MainWindow.open() called");
    	
    	display = new Display(); 
        //open shell and prevent resizing: 
        final Shell shell = new Shell(display, SWT.CLOSE | SWT.MIN | SWT.TITLE | SWT.RESIZE); 
           
        //set shell to maximum size: 
        shell.setMaximized(true);
        
        //set icon:
        shell.setImage(Environment.ICON);
           
        //set main window title: 
        shell.setText("Egocenteric Network"); 
        
        createMenu(shell); 
         
        GridLayout mainLayout = new GridLayout(5, true); 
        mainLayout.marginWidth = 0; 
        mainLayout.marginHeight = 0; 
        shell.setLayout(mainLayout);
                   
        final Composite leftSide = new Composite(shell, SWT.BORDER);
        GridLayout leftSideLayout = new GridLayout(1, false); 
        leftSideLayout.horizontalSpacing = 0; 
        leftSideLayout.verticalSpacing = 0; 
        leftSideLayout.marginWidth = 0; 
        leftSideLayout.marginHeight = 0; 
        leftSide.setLayout(leftSideLayout); 
           
        GridData leftSideGridData = new GridData(SWT.FILL, SWT.FILL, true, true); 
        leftSide.setLayoutData(leftSideGridData);
                          
        final Composite rightSide = new Composite(shell, SWT.NONE);
        GridLayout rightSideLayout = new GridLayout(1, false);
        rightSideLayout.horizontalSpacing = 0; 
        rightSideLayout.verticalSpacing = 0; 
        rightSideLayout.marginWidth = 0; 
        rightSideLayout.marginHeight = 0; 
        rightSide.setLayout(rightSideLayout);
        rightSide.setBackgroundImage(Environment.BG_MAIN);
        rightSide.setBackgroundMode(SWT.INHERIT_NONE);
           
        GridData rightSideGridData = new GridData(SWT.FILL, SWT.FILL, true, true);
        rightSideGridData.horizontalSpan = 4;
        rightSide.setLayoutData(rightSideGridData);
 
        //set rightSide to 80% of screen size when painting:
        rightSide.addPaintListener(new PaintListener() {
             
            @Override
            public void paintControl(PaintEvent e) {
                rightSide.setSize((int)Math.ceil(shell.getClientArea().width * 0.8), shell.getClientArea().height - Configurations.getDecreaseHeight());
            }
        });
        
        populateLeftSidePane(shell, leftSide);
        
        //set leftSide to 20% of screen size when painting:
        leftSide.addPaintListener(new PaintListener() {
             
            @Override
            public void paintControl(PaintEvent e) {
                leftSide.setSize((int)Math.ceil(shell.getClientArea().width * 0.2), shell.getClientArea().height - Configurations.getDecreaseHeight());
                for (int i = 0; i < width.length; i++) {
                    if (width[i] > 0)
                        requestsTable.getColumn(i).setWidth(width[i]);
                    else {
                        int totalNonZeroWidth = 0;
                        for (int j = 0; j < width.length; totalNonZeroWidth += width[j++]);
                        requestsTable.getColumn(i).setWidth(leftSide.getClientArea().width - totalNonZeroWidth);
                         
                    }
                }
            }
        });
        
        tabs = new TabFolder(rightSide, SWT.NONE);
        tabs.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        tabs.setVisible(false);
        
        tabs.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
				if (event.item != null) {
					BasicTab tab = (BasicTab)event.item.getData(BasicTab.KEY_TAB);
					if (tab != null) {
						if (tab instanceof ProfileTab<?>) {
						//selection changed to a profile tab:
						saveMenuItem.setEnabled(((ProfileTab<?>)tab).isSaveButtonEnabled());
						} else {
							//a non profile tab was selected:
							saveMenuItem.setEnabled(false);
						}
					}
				}
			}
		});
        
        shell.open(); 

    	Log.writeLineToLog("Shell opened");

        shell.addListener(SWT.Close, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
				
				if (Environment.unsavedProfiles > 0) {
					EgoNetworkMessageBox mbox = new EgoNetworkMessageBox
							(shell, SWT.ICON_QUESTION, SWT.YES | SWT.NO);
					mbox.setText("Exiting Egocenteric Networks");
					mbox.setMessage("Are you sure you want to exit without saving?");
					if (mbox.open() == SWT.NO) {
						event.doit = false;
						return;
					}
				}
				
				Log.closeLog();
				ThreadPool.closeNow();
			}
		});
           
        while (!shell.isDisposed()) { 
        	try {
	            if (!display.readAndDispatch()) 
	                display.sleep(); 
        	} catch (Exception e) {
    			Log.writeExceptionToLog(e);
    			//notify user:
    			EgoNetworkMessageBox enmx =
    					new EgoNetworkMessageBox(MainWindow.getDisplay().getShells()[0], SWT.ICON_ERROR, SWT.OK);
            	enmx.setText("Unexpected Error");
            	enmx.setMessage("Unexpected error has occurred. We're sorry for the inconvenience.");
            	enmx.open();
            	//after dialog is closed, re-issue loop!
        	}
        }
        display.dispose(); 
    } 
       
    private static void createMenu(final Shell window) { 
   
    	Log.writeLineToLog("Creating MainWindow's menu");

        Menu menu = new Menu(window, SWT.BAR); 
        
        MenuItem fileMenuHeader = new MenuItem(menu, SWT.CASCADE); 
        fileMenuHeader.setText("&File"); 
           
        Menu fileMenu = new Menu(window, SWT.DROP_DOWN); 
        fileMenuHeader.setMenu(fileMenu); 
           
        MenuItem newMenuItem = new MenuItem(fileMenu, SWT.CASCADE); 
        newMenuItem.setText("New"); 
           
        Menu newMenu = new Menu(newMenuItem); 
        newMenuItem.setMenu(newMenu); 
           
        MenuItem newFacebookMenuItem = new MenuItem(newMenu, SWT.PUSH); 
        newFacebookMenuItem.setText("Facebook Profile"); 
        newFacebookMenuItem.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
		    	Log.writeLineToLog("NewFacebookMenuItem clicked");
				new FacebookTab(getFacebookRequestHandler(window)).issueNewProfile(window);
			}
		});
           
        MenuItem newLinkedinMenuItem = new MenuItem(newMenu, SWT.PUSH); 
        newLinkedinMenuItem.setText("Linkedin Profile");
        newLinkedinMenuItem.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
		    	Log.writeLineToLog("new LinkedinMenuItem clicked");
				new LinkedinTab(getLinkedinRequestHandler(window)).issueNewProfile(window);
			}
		});
           
        new MenuItem(fileMenu, SWT.SEPARATOR); 
           
        MenuItem openMenuItem = new MenuItem(fileMenu, SWT.PUSH); 
        openMenuItem.setText("Open Profile...\tCtrl+O"); 
        openMenuItem.setAccelerator(SWT.MOD1 + 'O'); 
        openMenuItem.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
				
		    	Log.writeLineToLog("openMenuItem clicked (or CTRL+O)");

				FileOpenDialog fod = new FileOpenDialog(window);
				final String filename = (String)fod.open();
				if (filename != null) {
					
					SocialNetworks network = ProfileFile.getSocialNetworkOfFile(filename);
					
					if (network != null) {
						
						String id = ProfileFile.getProfileIDFromFileName(filename, network);
						TabItem ti = getTab(id);
						if (ti != null) {
							setTabFocus(id);
							return;
						}

						TableItem ti2 = getTableItem(id);
						if (ti2 != null) {
							requestsTable.setSelection(ti2);
							requestsTable.notifyListeners(SWT.MouseDoubleClick, new Event());
							return;
						}
						
						final IRequestGUI _networkRequestGUI =
								(network == SocialNetworks.Facebook ? getFacebookRequestHandler(window) : getLinkedinRequestHandler(window));
						_networkRequestGUI.onRequestIssued();
						_networkRequestGUI.onResponseReceived(ProfileFile.getProfileNameFromFileName(filename, network));

						ThreadPool.submitTask(new EgoNetworkCallable<Future<Void>, Void>() {
							
							@Override
							public Void call() throws Exception {
								try {
									MainProfile<?> profile = ProfileFile.openFile(filename);
									_networkRequestGUI.onResponseFinishedSuccessfuly(true, profile);
								} catch(Exception e) {
									_networkRequestGUI.onResponseFailed(true, (e.getMessage() != null ? e.getMessage() : "Error opening file."));
								}
								return null;
							}
						});
					}
				}
				
			}
		});
        
        MenuItem importExcelMenuItem = new MenuItem(fileMenu, SWT.PUSH); 
        importExcelMenuItem.setText("Import Excel\tCtrl+E"); 
        importExcelMenuItem.setAccelerator(SWT.MOD1 + 'E');
        importExcelMenuItem.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event arg0) {
				
				
				Log.writeLineToLog("importExcelMenuItem clicked (or CTRL+E)");
				
				//prompt user for file:
				FileDialog fileDialog = new FileDialog(window, SWT.OPEN);
				fileDialog.setFilterNames(new String[] { "Excel File (*.xls, *.xlsx)" });
				fileDialog.setFilterExtensions(new String[] { "*.xls*" });
				final String filename = fileDialog.open();
				
				if (filename != null) {
					
					ThreadPool.submitTask(new EgoNetworkCallable<Future<Void>, Void>() {
						
						@Override
						public Void call() throws Exception {
							IExcelRead excelReadHandler = new IExcelRead() {
								
								IRequestGUI requestGUI = null;
								
								@Override
								public void onNetworkDetected(SocialNetworks network) {
									requestGUI = 
											(network == SocialNetworks.Facebook ? getFacebookRequestHandler(window) : getLinkedinRequestHandler(window));
									requestGUI.onRequestIssued();
								}

								@Override
								public void onProfileName(String name) {
									requestGUI.onResponseReceived(name);
								}

								@Override
								public void onFinish(MainProfile<?> profile) {
									requestGUI.onResponseFinishedSuccessfuly(true, profile);
								}

								@Override
								public void onFailure(final ExcelCastException e) {
									Log.writeExceptionToLog(e);
									if (requestGUI != null) {
										requestGUI.onResponseFailed(true, e.getMessage());
									} else {
										display.asyncExec(new Runnable() {
											@Override
											public void run() {
												displayErrorMessageBox(window, e.getMessage());
											}
										});
									}
								}
								
							};
							try {
								ExcelReadUtils.readProfile(filename, excelReadHandler);
							} catch (ExcelCastException e) {
								excelReadHandler.onFailure(e);
							}
							return null;
						}
					});
					
				}
				
			}
			
		});
           
        new MenuItem(fileMenu, SWT.SEPARATOR); 
        
        saveMenuItem = new MenuItem(fileMenu, SWT.PUSH); 
        saveMenuItem.setText("Save\tCtrl+S");
        saveMenuItem.setAccelerator(SWT.MOD1 + 'S');
        saveMenuItem.setEnabled(false);
        saveMenuItem.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event event) {

				Log.writeLineToLog("saveMenuItem clicked (or CTRL+S)");

				if (tabs.getSelectionIndex() >= 0) {
					ProfileTab<?> tab =
							(ProfileTab<?>)tabs.getItem(tabs.getSelectionIndex())
							.getData(BasicTab.KEY_TAB);
					tab.issueSave();
				}
			}
		});
        
        new MenuItem(fileMenu, SWT.SEPARATOR); 
           
        MenuItem exitMenuItem = new MenuItem(fileMenu, SWT.PUSH); 
        exitMenuItem.setText("Exit"); 
        exitMenuItem.addListener(SWT.Selection, new Listener() { 
               
            @Override
            public void handleEvent(Event arg0) { 
                window.close(); 
            }
        }); 
           
        MenuItem helpMenuHeader = new MenuItem(menu, SWT.CASCADE); 
        helpMenuHeader.setText("&Help"); 
           
        Menu helpMenu = new Menu(window, SWT.DROP_DOWN); 
        helpMenuHeader.setMenu(helpMenu); 
        
        MenuItem visualizationMenuItem = new MenuItem(helpMenu, SWT.PUSH);
        visualizationMenuItem.setText("Visualization Preferences");
        visualizationMenuItem.addListener(SWT.Selection, new Listener() {

			@Override
			public void handleEvent(Event arg0) {
				new VisualizationPreferencesDialog(window).open();
				
			}
        	
        });
        
        MenuItem excelHelpItem = new MenuItem(helpMenu, SWT.PUSH);
        excelHelpItem.setText("Excel import help");
        excelHelpItem.addListener(SWT.Selection, new Listener() {

			@Override
			public void handleEvent(Event arg0) {
				new ExcelHelpDialog(window).open();
			}
        	
        });
        
        
        new MenuItem(helpMenu, SWT.SEPARATOR); 

        MenuItem aboutMenuItem = new MenuItem(helpMenu, SWT.PUSH); 
        aboutMenuItem.setText("About");
        aboutMenuItem.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
				new AboutDialog(window).open();
			}
		});
           
        window.setMenuBar(menu); 
    } 
   
    private static void populateLeftSidePane(final Shell window, final Composite leftSide) {
    	
    	Log.writeLineToLog("Populating Left Side Pane");

        Font generalFont = new Font(display, "Ariel", 11, SWT.BOLD);
         
        final Composite networksTitleComposite = new Composite(leftSide, SWT.NONE);
        networksTitleComposite.setBackgroundImage(Environment.BG_TITLE);
        networksTitleComposite.setLayout(new GridLayout(1, false));
        networksTitleComposite.setBackgroundMode(SWT.INHERIT_FORCE);
        networksTitleComposite.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
         
        Label networksTitleLabel = new Label(networksTitleComposite, SWT.NONE);
        networksTitleLabel.setText("Social Networks");
        networksTitleLabel.setForeground(Environment.COLOR_WHITE);
        networksTitleLabel.setFont(generalFont);
         
        final Composite networksComposite = new Composite(leftSide, SWT.NONE);
        networksComposite.setBackground(Environment.COLOR_WHITE);
        networksComposite.setBackgroundMode(SWT.INHERIT_FORCE);
        networksComposite.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
         
        GridLayout networksCompositeLayout = new GridLayout(1, false);
        networksCompositeLayout.marginBottom = 15;
        networksCompositeLayout.marginTop = 15;
        networksCompositeLayout.marginRight = 15;
        networksCompositeLayout.marginLeft = 15;
        networksCompositeLayout.verticalSpacing = 10;
        networksComposite.setLayout(networksCompositeLayout);
                         
        Image facebookButtonImg = Environment.FACEBOOK_PROFILE;
        GridData facebookButtonData = new GridData(SWT.FILL, SWT.FILL, true, false);
        facebookButtonData.heightHint = facebookButtonImg.getImageData().height + 10;
         
        Button facebookButton = new Button(networksComposite, SWT.PUSH | SWT.FLAT); 
        facebookButton.setImage(facebookButtonImg);
        facebookButton.setText("    Facebook");
        facebookButton.setFont(generalFont);
        facebookButton.setLayoutData(facebookButtonData);
                   
        Image linkedinButtonImg = Environment.LINKEDIN_PROFILE;
        GridData linkedinButtonData = new GridData(SWT.FILL, SWT.FILL, true, false);
        linkedinButtonData.heightHint = linkedinButtonImg.getImageData().height + 10;
         
        Button linkedinButton = new Button(networksComposite, SWT.PUSH); 
        linkedinButton.setImage(linkedinButtonImg);
        linkedinButton.setText("    Linkedin");
        linkedinButton.setFont(generalFont);
        linkedinButton.setLayoutData(linkedinButtonData);
         
        final Composite profileRequestsTitleComposite = new Composite(leftSide, SWT.NONE); 
        profileRequestsTitleComposite.setBackgroundImage(Environment.BG_TITLE);
        profileRequestsTitleComposite.setLayout(new GridLayout(1, false));
        profileRequestsTitleComposite.setBackgroundMode(SWT.INHERIT_FORCE);
        profileRequestsTitleComposite.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
         
        Label profileRequestsTitleLabel = new Label(profileRequestsTitleComposite, SWT.NONE);
        profileRequestsTitleLabel.setText("Egocenteric Profile Requests");
        profileRequestsTitleLabel.setForeground(Environment.COLOR_WHITE);
        profileRequestsTitleLabel.setFont(generalFont);
                  
        requestsTable = new Table(leftSide,  SWT.SINGLE | SWT.V_SCROLL | SWT.FULL_SELECTION);
        requestsTable.setLinesVisible(true);
        requestsTable.setHeaderVisible(true);
        requestsTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        requestsTable.setBackground(Environment.COLOR_TABLE_BG);
        requestsTable.setBackgroundMode(SWT.INHERIT_FORCE);
        requestsTable.addListener(SWT.Paint, new Listener() {
             
            @Override
            public void handleEvent(Event event) {
                requestsTable.setSize(requestsTable.getClientArea().width,
                        window.getClientArea().height - (networksTitleComposite.getClientArea().height
                                             + networksComposite.getClientArea().height
                                             + profileRequestsTitleComposite.getClientArea().height));
            }
        });
                 
        for (int i = 0; i < columns.length; i++) {
            final TableColumn column = new TableColumn(requestsTable, SWT.NONE);
            column.setText(columns[i]);
            column.setAlignment(alignments[i]);
            column.setResizable(false);
        }
                
        requestsTable.addMouseListener(new MouseListener() {
			
			@Override
			public void mouseUp(MouseEvent e) {
				TableItem[] selectedItem = requestsTable.getSelection();
				if (selectedItem.length == 1) {
					selectedItem[0].setBackground(Environment.COLOR_TABLE_ROW);
				}
			}
			
			@Override
			public void mouseDown(MouseEvent e) {
				
			}
			
			@SuppressWarnings("unchecked")
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				
		    	Log.writeLineToLog("requestsTable item double clicked");
				
				TableItem[] selectedItems = requestsTable.getSelection();
				if (selectedItems.length == 1) { //should not be able to be different
					MainProfile<?> profile = (MainProfile<?>)selectedItems[0].getData(KEY_PROFILE);
					if (profile != null) {
				    	Log.writeLineToLog("requestsTable profile ID is " + profile.getID());
						if (selectedItems[0].getData(KEY_PROFILE_TYPE).equals(KEY_FACEBOOK)) {
							//facebook profile:
							tabs.setVisible(true);
							if (getTab(profile.getID() + "") == null) {
								//tab not open, open one:
								FacebookProfileTab fpt = new FacebookProfileTab((MainProfile<Long>)profile);
								fpt.createTab(tabs);
							} else {
								//tab open, focus it:
								setTabFocus(profile.getID() + "");
							}							
						} else if (selectedItems[0].getData(KEY_PROFILE_TYPE).equals(KEY_LINKEDIN)) {
							//linkedin profile:
							tabs.setVisible(true);
							if (getTab(profile.getID() + "") == null) {
								//tab not open, open one:
								LinkedinProfileTab lpt = new LinkedinProfileTab((MainProfile<String>)profile);
								lpt.createTab(tabs);
							} else {
								//tab open, focus it:
								setTabFocus(profile.getID() + "");
							}														
						}
					} else {
						String errorMessage = (String)selectedItems[0].getData(KEY_ERROR);
						if (errorMessage != null) {
							displayErrorMessageBox(window, errorMessage);
						}
					}
				}
			}
		});
                                        
        facebookButton.addListener(SWT.Selection, new Listener() {
             
            @Override
            public void handleEvent(Event e) {
            	
		    	Log.writeLineToLog("facebookButton clicked");
            	
            	if (getTab(KEY_FACEBOOK) == null) {
            	
	                FacebookTab t = new FacebookTab(getFacebookRequestHandler(window));
                    t.createTab(tabs);
                    t.setKey(KEY_FACEBOOK);
                    tabs.setVisible(true);
            	
                } else {
                	setTabFocus(KEY_FACEBOOK);
                }
            }
        });
         
        linkedinButton.addListener(SWT.Selection, new Listener() {
            
            @Override
            public void handleEvent(Event e) {

            	Log.writeLineToLog("linkedinButton clicked");

            	if (getTab(KEY_LINKEDIN) == null) {
            	
	            	LinkedinTab t = new LinkedinTab(getLinkedinRequestHandler(window));

                    t.createTab(tabs);
            		t.setKey(KEY_LINKEDIN);
            		tabs.setVisible(true);
            		
            	} else {
            		setTabFocus(KEY_LINKEDIN);
            	}
            }
        });
    }
    
    private static IRequestGUI getFacebookRequestHandler(final Shell window) {
    	return getNetworkRequestHandler(window, Environment.ICON_FACEBOOK, KEY_FACEBOOK,
    			new INewProfileTab() {
					
					@SuppressWarnings("unchecked")
					@Override
					public ProfileTab<?> instanceTab(MainProfile<?> profile) {
						return new FacebookProfileTab((MainProfile<Long>)profile);
					}
				});
    }
    
    private static IRequestGUI getLinkedinRequestHandler(final Shell window) {
    	return getNetworkRequestHandler(window, Environment.ICON_LINKEDIN, KEY_LINKEDIN,
    			new INewProfileTab() {
					
					@SuppressWarnings("unchecked")
					@Override
					public ProfileTab<?> instanceTab(MainProfile<?> profile) {
						return new LinkedinProfileTab((MainProfile<String>)profile);
					}
				});  	
    }
    
    interface INewProfileTab { ProfileTab<?> instanceTab(MainProfile<?> profile); }
    private static IRequestGUI getNetworkRequestHandler(final Shell window,
    		final Image netIcon, final String key, final INewProfileTab newTab) {
    	
    	return new IRequestGUI() {
    		
        	private TableItem requestItem;
        	
			@Override
			public void onRequestIssued() {
				display.asyncExec(new Runnable() {
					@Override
					public void run() {
				    	Log.writeLineToLog("onRequestIssued()");
						requestItem = new TableItem(requestsTable, SWT.NONE);
						requestItem.setBackground(Environment.COLOR_TABLE_ROW);
						requestItem.setImage(0, netIcon);
						requestItem.setImage(1, Environment.ICON_HOURGLASS);
						DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
						requestItem.setText(3, dateFormat.format(new Date()));
					}
				});
			}

			@Override
			public void onResponseReceived(final String profileName) {
				display.asyncExec(new Runnable() {
					
					@Override
					public void run() {
				    	Log.writeLineToLog("onResponseReceived: " + profileName);
						requestItem.setText(2, profileName);
					}
				});
			}

			@Override
			public void onResponseFinishedSuccessfuly(final boolean dialogShown, final MainProfile<?> profile) {
				display.asyncExec(new Runnable() {

					@Override
					public void run() {
						Log.writeLineToLog("onResponseFinishedSuccessfuly(): dialogShown?: " + dialogShown);
						requestItem.setImage(1, Environment.ICON_OK);
						if (dialogShown) {
							//TODO: what if tab is already opened
							ProfileTab<?> pt = newTab.instanceTab(profile);
							pt.createTab(tabs);
							pt.setKey(profile.getID() + "");
							tabs.setVisible(true);
						}
						requestItem.setData(KEY_PROFILE, profile);
						requestItem.setData(KEY_PROFILE_TYPE, key);
					}
					
				});
			}
			
			@Override
			public void onResponseFailed(final boolean dialogShown, final String errorMessage) {
				display.asyncExec(new Runnable() {
					
					@Override
					public void run() {
				    	Log.writeLineToLog("onResponseFailed(): dialogShown?: " + dialogShown);
						requestItem.setImage(1, Environment.ICON_ERROR);
						requestItem.setData(KEY_ERROR, errorMessage);
						if (dialogShown) {
							displayErrorMessageBox(window, errorMessage);
						}	
					}
				});
			}
			
		};
    }
    
    private static TabItem getTab(String key) {
    	TabItem[] items = tabs.getItems();
    	for (TabItem ti : items) {
    		if (ti.getData(key) != null) {
    			return ti;
    		}
    	}
    	Log.writeLineToLog("getTab() returning null on key " + key);
    	return null;
    }
    
    private static void setTabFocus(String key) {
    	TabItem[] items = tabs.getItems();
    	for (TabItem ti : items) {
    		if (ti.getData(key) != null) {
    			tabs.setSelection(ti);
    			break;
    		}
    	}
    }
    
    private static TableItem getTableItem(String id) {
    	TableItem[] items = requestsTable.getItems();
    	for (TableItem ti : items) {
    		Object data = ti.getData(KEY_PROFILE);
    		if (data != null && (((Profile<?>)data).getID() + "").equals(id)) {
    			return ti;
    		}
    	}
    	Log.writeLineToLog("getTableItem() returning null on id " + id);
    	return null;
    }
    
    private static void displayErrorMessageBox(Shell shell, String errorMessage) {
    	Log.writeLineToLog("displaying error message box: " + errorMessage);
		EgoNetworkMessageBox mbox = new EgoNetworkMessageBox(shell, SWT.ICON_ERROR, SWT.OK);
		mbox.setText("Error");
		mbox.setMessage(errorMessage == null ? "" : errorMessage);
		mbox.open();
    }
    
    static Display getDisplay() {
    	return display;
    }
    
    static void setSaveMenuItemEnabled(boolean enabled) {
    	saveMenuItem.setEnabled(enabled);
    }
    
}